package _15_generics._15_10;

/**
 * 原生类型和无界通配符的类型之间的差异
 */
public class _08_Wildcards {

    static void rawArgs(_02_Holder holder,Object arg){
        //Unchecked call to 'set(T)' as a member of raw type '_15_generics._15_10._02_Holder'
        holder.set(arg);
        holder.set(new _08_Wildcards());

        //The type information has been lost
        Object o = holder.get();
    }

    static void unboundedArg(_02_Holder<?> holder,Object arg){
//        holder.set(arg);
//        holder.set(new _08_Wildcards());
        //The type information has been lost
        Object o = holder.get();
    }

    static <T> T exact1(_02_Holder<T> holder) {
        T t = holder.get();
        return t;
    }

    static <T> T exact2(_02_Holder<T> holder, T arg) {
        holder.set(arg);
        T t = holder.get();
        return t;
    }

    static <T> T wildSubtype(_02_Holder<? extends T> holder, T arg) {
        T t = holder.get();
        return t;
    }

    static <T> void wildSupertype(_02_Holder<? super T> holder, T arg) {
        holder.set(arg);
        // T t = holder.get();  // Error:
        //   Incompatible types: found Object, required T
        // OK, but type information has been lost:
        Object obj = holder.get();
    }

    public static void main(String[] args) {
        _02_Holder raw = new _02_Holder<Long>();
        // Or:
        raw = new _02_Holder();
        _02_Holder<Long> qualified = new _02_Holder<>();
        _02_Holder<?> unbounded = new _02_Holder<Long>();
        _02_Holder<? extends Long> bounded = new _02_Holder<>();
        Long lng = 1L;

        rawArgs(raw, lng);
        rawArgs(qualified, lng);
        rawArgs(unbounded, lng);
        rawArgs(bounded, lng);

        unboundedArg(raw, lng);
        unboundedArg(qualified, lng);
        unboundedArg(unbounded, lng);
        unboundedArg(bounded, lng);

         Object r1 = exact1(raw); // Warnings:
        //   Unchecked conversion from Holder to Holder<T>
        //   Unchecked method invocation: exact1(Holder<T>)
        //   is applied to (Holder)
        Long r2 = exact1(qualified);
        Object r3 = exact1(unbounded); // Must return Object
        Long r4 = exact1(bounded);

        // Long r5 = exact2(raw, lng); // Warnings:
        //   Unchecked conversion from Holder to Holder<Long>
        //   Unchecked method invocation: exact2(Holder<T>,T)
        //   is applied to (Holder,Long)
        Long r6 = exact2(qualified, lng);
//         Long r7 = exact2(unbounded, lng); // Error:
        //   exact2(Holder<T>,T) cannot be applied to
        //   (Holder<capture of ?>,Long)
        // Long r8 = exact2(bounded, lng); // Error:
        //   exact2(Holder<T>,T) cannot be applied
        //   to (Holder<capture of ? extends Long>,Long)

         Long r9 = wildSubtype(raw, lng); // Warnings:
        //   Unchecked conversion from Holder
        //   to Holder<? extends Long>
        //   Unchecked method invocation:
        //   wildSubtype(Holder<? extends T>,T) is
        //   applied to (Holder,Long)
        Long r10 = wildSubtype(qualified, lng);
        // OK, but can only return Object:
        Object r11 = wildSubtype(unbounded, lng);
        Long r12 = wildSubtype(bounded, lng);

         wildSupertype(raw, lng); // Warnings:
        //   Unchecked conversion from Holder
        //   to Holder<? super Long>
        //   Unchecked method invocation:
        //   wildSupertype(Holder<? super T>,T)
        //   is applied to (Holder,Long)
        wildSupertype(qualified, lng);
        // wildSupertype(unbounded, lng); // Error:
        //   wildSupertype(Holder<? super T>,T) cannot be
        //   applied to (Holder<capture of ?>,Long)
//         wildSupertype(bounded, lng); // Error:
        //   wildSupertype(Holder<? super T>,T) cannot be
        //  applied to (Holder<capture of ? extends Long>,Long)
    }
}
